package ch.areion.areionapp.io;

import ioio.lib.api.DigitalOutput;
import ioio.lib.api.DigitalInput;
import ioio.lib.api.IOIO;
import ioio.lib.api.exception.ConnectionLostException;
import ch.areion.areionapp.communication.Monitor;
import ch.areion.common.message.Module;
import ch.areion.common.message.Type;
import ch.areion.common.message.Version;

public class IO implements IIO {
	private IOIO ioio;

	private DigitalOutput BIT_0;
	private DigitalOutput BIT_1;
	private DigitalOutput BIT_2;
	private DigitalOutput BIT_3;
	private DigitalInput CAP_SIGNAL;

	private static final boolean ACTIVATE = true;
	private static final boolean DEACTIVATE = !ACTIVATE;

	public IO(IOIO ioio) throws ConnectionLostException {
		Monitor.getInstance().add(Version.V01, Type.INFO, Module.IO,
		    "Starting IO Module");
		this.ioio = ioio;

		BIT_0 = this.ioio.openDigitalOutput(45);
		BIT_1 = this.ioio.openDigitalOutput(44);
		BIT_2 = this.ioio.openDigitalOutput(43);
		BIT_3 = this.ioio.openDigitalOutput(42);
		CAP_SIGNAL = this.ioio.openDigitalInput(6, DigitalInput.Spec.Mode.PULL_DOWN);

		Monitor.getInstance().add(Version.V01, Type.INFO, Module.IO,
		    "IO Module ready");
	}
	
	@Override
	public void setDisplayBoxnumber(BoxNumber boxnumber)
	    throws ConnectionLostException {
		Monitor.getInstance().add(Version.V01, Type.INFO, Module.IO, "Number",
		    String.format("%d", boxnumber.getValue()));
		setNumber(boxnumber.getValue());
	}

	private void setNumber(int n) throws ConnectionLostException {
		if(ioio != null) {
			n = n % 10;
			Monitor.getInstance().add(Version.V01, Type.INFO, Module.IO,
			    String.format("Setting output to number %d", n));

			BIT_0.write((n & 1) == 1 ? ACTIVATE : DEACTIVATE);
			Monitor.getInstance().add(Version.V01, Type.INFO, Module.IO, "Pin 0",
			    String.format("%b", ((n & 1)==1)));
			BIT_1.write((n & 2) == 2 ? ACTIVATE : DEACTIVATE);
			Monitor.getInstance().add(Version.V01, Type.INFO, Module.IO, "Pin 1",
			    String.format("%b", ((n & 2) == 2)));
			BIT_2.write((n & 4) == 4 ? ACTIVATE : DEACTIVATE);
			Monitor.getInstance().add(Version.V01, Type.INFO, Module.IO, "Pin 2",
			    String.format("%b", ((n & 4) == 4)));
			BIT_3.write((n & 8) == 8 ? ACTIVATE : DEACTIVATE);
			Monitor.getInstance().add(Version.V01, Type.INFO, Module.IO, "Pin 3",
			    String.format("%b", ((n & 8) == 8)));
		}
	}

	@Override
	public void resetDisplayBoxnumber() throws ConnectionLostException {
		setDisplayBoxnumber(BoxNumber.NONE);
	}

	@Override
	public void setError() throws ConnectionLostException {
		setDisplayBoxnumber(BoxNumber.ERROR);
	}
	
	@Override
	public void waitUntilCAP(boolean value) throws InterruptedException, ConnectionLostException
	{
		CAP_SIGNAL.waitForValue(value);
	}
	
	@Override
	public boolean readCAP() throws InterruptedException, ConnectionLostException
	{
		return CAP_SIGNAL.read();
	}

	@Override
	public void disconnect() throws ConnectionLostException, InterruptedException {
		Monitor.getInstance().add(Version.V01, Type.INFO, Module.IO,
		    "Closing IO module");
		if(BIT_0 != null)
			BIT_0.close();
		if(BIT_1 != null)
			BIT_1.close();
		if(BIT_2 != null)
			BIT_2.close();
		if(BIT_3 != null)
			BIT_3.close();
		
		if(CAP_SIGNAL != null)
			CAP_SIGNAL.close();
		Monitor.getInstance().add(Version.V01, Type.INFO, Module.IO,
		    "IO module closed");
	}

}
